﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.ComponentModel;

namespace Pavilion.DesignerTool
{
    public class AnimationData : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public string Name
        {
            get { return Animation.Name; }
            set
            {
                if (Animation.Name == value)
                    return;

                Animation.Name = value;
                OnPropertyChanged("Name");
            }
        }
        public Animation Animation { get; set; }
        public NotifiableCollection<FrameData> FrameDataCollection { get; private set; }
        public UndoRedoController UndoRedoController { get; private set; }

        private List<Frame> OriginalFrameList { get; set; }
        private string OriginalName { get; set; }

        public AnimationData(Animation animation)
        {
            this.Animation = animation;
            FrameDataCollection = new NotifiableCollection<FrameData>();
            OriginalName = animation.Name;

            foreach (Frame frame in Animation.FrameList)
                FrameDataCollection.Add(new FrameData(frame));

            UndoRedoController = new UndoRedoCollection<FrameData>(FrameDataCollection);
            OriginalFrameList = new List<Frame>(animation.FrameList);

            FrameDataCollection.Added += (FrameData frameData, int index) => { this.Animation.FrameList.Insert(index, frameData.Frame); };
            FrameDataCollection.Removed += (FrameData frameData, int index) => { this.Animation.FrameList.RemoveAt(index); };
            FrameDataCollection.Moved += (int oldIndex, int newIndex) => { this.Animation.FrameList.Move(oldIndex, newIndex); };
        }

        public void Dispose()
        {
            Animation.Dispose();
        }

        public FrameData CreateFrameData()
        {
            Microsoft.Xna.Framework.Graphics.Texture2D texture = CTexture2D.CreateTexture(Animation.DefaultFrameWidth, Animation.DefaultFrameHeight);

            Frame frame = new Frame()
            {
                OriginX = Animation.DefaultFrameOrigin.X,
                OriginY = Animation.DefaultFrameOrigin.Y
            };

            frame.TextureList.Add(new CTexture2D(texture));
            return new FrameData(frame);
        }

        public void Save(string resourceRawDataPath, string fullResourcePath)
        {
            string fullAnimationRawDataPath = resourceRawDataPath + Animation.Name;
            PrepareAnimationForSaving(fullAnimationRawDataPath, fullResourcePath);

            int count = 0;

            foreach (FrameData frameData in FrameDataCollection)
                frameData.Save(fullAnimationRawDataPath + @"\" + count++);
        }

        private void PrepareAnimationForSaving(string fullAnimationRawDataPath, string fullResourcePath)
        {
            if (IsAnimationChanged)
                UpdateCurrentDirectory(fullAnimationRawDataPath, fullResourcePath);

            DeleteAllRemovedFrames(fullAnimationRawDataPath);
            DeleteAllDifferentIndexFrames(fullAnimationRawDataPath);

            ResetSaveTrackingPoint();
        }

        private void ResetSaveTrackingPoint()
        {
            OriginalFrameList.Clear();
            OriginalFrameList.AddRange(Animation.FrameList);
        }

        private void UpdateCurrentDirectory(string fullAnimationRawDataPath, string fullResourcePath)
        {
            string originalSavePath = fullResourcePath + @"Raw Data\" + OriginalName;

            if (OriginalName != Animation.Name)
                try { Directory.Move(originalSavePath, fullAnimationRawDataPath); } catch { }
            
            if (!Directory.Exists(fullAnimationRawDataPath))
                Directory.CreateDirectory(fullAnimationRawDataPath);

            OriginalName = Animation.Name;
        }

        private void DeleteAllDifferentIndexFrames(string fullAnimationRawDataPath)
        {
            for (int i = 0; i < Animation.FrameList.Count; i++)
            {
                if (IsFrameDifferentIndex(i) && !IsFrameNew(i))
                    Directory.Delete(fullAnimationRawDataPath + @"\" + OriginalFrameList.IndexOf(Animation.FrameList[i]).ToString(), true);
            }
        }

        private void DeleteAllRemovedFrames(string fullAnimationRawDataPath)
        {
            foreach (Frame frame in OriginalFrameList)
            {
                if (!Animation.FrameList.Contains(frame))
                    Directory.Delete(fullAnimationRawDataPath + @"\" + OriginalFrameList.IndexOf(frame).ToString(), true);
            }
        }

        private bool IsFrameDifferentIndex(int frameIndex) 
        {
            try { return Animation.FrameList[frameIndex] != OriginalFrameList[frameIndex]; }
            catch { return true; }
        }

        private bool IsFrameNew(int frameIndex) { return !OriginalFrameList.Contains(Animation.FrameList[frameIndex]); }

        public bool IsAnimationChanged
        {
            get
            {
                if (Animation.Name != OriginalName)
                    return true;

                return Enumerable.SequenceEqual<Frame>(Animation.FrameList, OriginalFrameList);
            }
        }

        public override string ToString()
        {
            return Animation.ToString();
        }

        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
